"""
excel_parser.py 定向越野积分赛Excel数据解析模块
"""
import logging
import os
import shutil
from openpyxl import load_workbook, Workbook
from collections import defaultdict

# 配置日志
# 确保output目录存在
output_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'output')
os.makedirs(output_dir, exist_ok=True)

logging.basicConfig(
    filename=os.path.join(output_dir, 'data_parser.log'),
    level=logging.WARNING,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# 比赛规则参数
COMPETITION_RULES = {
    'time_limit': 10*10,
    'penalty': (0.5, 1),
    'valid_time': 12*10
}

class ExcelParser:
    def __init__(self, point_file: str, matrix_file: str):
        """Excel数据解析器
        使用示例:
        from data.excel_parser import ExcelParser
        
        # 初始化解析器 (需同时提供点位文件和矩阵文件)
        parser = ExcelParser(
            point_file="tests/test_data/valid_points.xlsx",
            matrix_file="tests/test_data/valid_matrix.xlsx"
        )
        
        # 加载并验证数据
        try:
            parser.load_data()
            graph_data = parser.get_graph_data()
        except StructureError as e:
            print(f"数据验证失败: {e}")
            
        :param point_file: 点位分值表路径
        :param matrix_file: 耗时矩阵表路径
        """
        self.point_file = point_file
        self.matrix_file = matrix_file
        self.points = []
        self.profits = {}
        self.time_matrix = defaultdict(dict)
        self.error_report = []

    def load_data(self):
        """总控加载流程"""
        try:
            self._load_point_data()
            self._load_matrix_data()
            self._generate_error_report()
            self.save_validated_data()
        except StructureError as e:
            logging.error(f"致命错误导致终止: {str(e)}")
            raise

    def _load_point_data(self):
        """加载点位信息表"""
        wb = load_workbook(self.point_file)
        ws = wb.active

        # 结构校验
        if ws.max_row < 2 or ws.max_column < 3:
            raise StructureError("表格1必须至少2行3列数据")

        # 解析点位标识行
        point_row = [cell.value for cell in ws[1]]
        self._validate_point_structure(point_row)

        # 解析分值行
        value_row = [cell.value for cell in ws[2]]
        self._process_point_values(point_row, value_row)

    def _validate_point_structure(self, points):
        """实施表格1结构校验"""
        # 校验S/F位置
        if points[0] != 'S' or points[1] != 'F':
            raise SFPositionError("首列必须为S，第二列必须为F")

        # 校验控制点格式
        for p in points[2:]:
            if not (isinstance(p, (int, str)) and (isinstance(p, int) or isinstance(p, str))):
                raise StructureError(f"控制点格式错误: {p}")

        # 检查唯一性
        seen = set()
        for p in points:
            if p in seen:
                raise StructureError(f"重复点位标识: {p}")
            seen.add(p)

        self.points = points

    def _process_point_values(self, points, values):
        """处理点位分值"""
        for point, value in zip(points, values):
            if point in ('S', 'F'):
                if value is not None and value != 0:
                    logging.warning(f"S/F分值应留空，检测到 {point}:{value} 已自动清零")
                self.profits[point] = 0
            else:
                if not isinstance(value, (int, float)) or value < 0:
                    raise StructureError(f"无效分值: {point}={value}")
                self.profits[point] = int(value)

    def _load_matrix_data(self):
        """加载耗时矩阵表"""
        wb = load_workbook(self.matrix_file)
        ws = wb.active

        # 获取起点列表（首列）
        start_points = [cell.value for cell in ws['A'][1:]]
        
        # 获取终点列表（首行）
        end_points = [cell.value for cell in ws[1][1:]]

        # 校验行列一致性
        if [str(p) for p in start_points] != [str(p) for p in self.points] or \
           [str(p) for p in end_points] != [str(p) for p in self.points]:
            raise MatrixIntegrityError("矩阵行列顺序与点位表不一致")

        # 解析矩阵数据
        for row_idx, row in enumerate(ws.iter_rows(min_row=2)):
            start_point = start_points[row_idx]
            for col_idx, cell in enumerate(row[1:]):  # 跳过首列
                end_point = end_points[col_idx]
                value = cell.value or 0.0  # 空单元格自动填充0

                # 特殊规则处理
                if start_point == 'F':
                    value = 0.0  # F行强制置零
                elif end_point == 'S':
                    if value != 0.0:
                        logging.warning(f"S作为终点的路径 {start_point}→S 耗时已清零")
                    value = 0.0

                # 数值格式校验
                if not self._is_valid_time(value):
                    raise TimeFormatError(f"无效耗时值: {start_point}→{end_point}={value}")

                self.time_matrix[start_point][end_point] = float(value)

    def _is_valid_time(self, value):
        """验证耗时格式"""
        # 检查是否为数字类型且非负数
        if not isinstance(value, (int, float)) or value < 0:
            return False
        else:
            return True    

    def _generate_error_report(self):
        """生成简略错误报告"""
        if self.error_report:
            with open('data_errors.txt', 'w') as f:
                f.write("\n".join(self.error_report))

    def get_graph_data(self):
        """生成图数据结构"""
        return {
            'nodes': [{'节点ID': p, '基础积分': self.profits.get(p, 0)} 
                     for p in self.points],
            'edges': [{'起点': s, '终点': d, '预计耗时(min)': t} 
                     for s in self.time_matrix for d, t in self.time_matrix[s].items() if t > 0]
        }

    def _ensure_output_directory(self):
        """确保输出目录存在"""
        if not os.path.exists('output'):
            os.makedirs('output')

    def _convert_points_to_strings(self):
        """将所有点位ID转换为字符串"""
        self.points = [str(p) for p in self.points]
        self.profits = {str(k): v for k, v in self.profits.items()}
        self.time_matrix = {
            str(s): {str(d): t for d, t in dest.items()}
            for s, dest in self.time_matrix.items()
        }

    def save_validated_data(self):
        """保存验证后的数据到output目录"""
        self._ensure_output_directory()
        self._convert_points_to_strings()

        # 删除已存在的文件
        for filename in ['valid_points.xlsx', 'valid_matrix.xlsx']:
            filepath = os.path.join('output', filename)
            if os.path.exists(filepath):
                os.remove(filepath)

        # 保存点位文件
        wb = Workbook()
        ws = wb.active
        ws.append(self.points)
        ws.append([self.profits[p] for p in self.points])
        wb.save(os.path.join('output', 'valid_points.xlsx'))

        # 保存矩阵文件
        wb = Workbook()
        ws = wb.active
        ws.append([''] + self.points)  # 首行为点位
        for start_point in self.points:
            row = [start_point] + [
                self.time_matrix[start_point].get(end_point, 0.0)
                for end_point in self.points
            ]
            ws.append(row)
        wb.save(os.path.join('output', 'valid_matrix.xlsx'))

# 异常体系
class StructureError(Exception):
    """致命错误基类"""

class SFPositionError(StructureError):
    """S/F位置错误"""

class MatrixIntegrityError(StructureError):
    """矩阵完整性错误"""

class TimeFormatError(StructureError):
    """时间格式错误"""
